package org.atovio.coolexam.service.impl;

import cn.hutool.core.util.ObjectUtil;
import org.atovio.coolexam.common.HttpCode;
import org.atovio.coolexam.common.Role;
import org.atovio.coolexam.entity.User;
import org.atovio.coolexam.exception.AuthenticationException;
import org.atovio.coolexam.exception.RequestException;
import org.atovio.coolexam.exception.ServiceException;
import org.atovio.coolexam.mapper.UserMapper;
import org.atovio.coolexam.service.UserService;
import org.atovio.coolexam.utils.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
@Transactional
public class UserServiceImpl implements UserService {


    private final UserMapper userMapper;

    @Autowired
    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public int getCount(Map<String, Object> criteria) {
        return userMapper.selectCountSelective(criteria);
    }

    @Override
    public List<User> getByRole(Role role) {
        return userMapper.selectSelective(Map.of("role", role));
    }

    @Override
    public List<User> getByRoleLikeUserName(Role role, String userName) {
        return userMapper.selectSelective(Map.of("role", role, "userName", userName));
    }

    @Override
    public User getByUserId(int userId) {
        return userMapper.selectByUserId(userId);
    }

    @Override
    public User addUser(User user) {
        if (Objects.isNull(user.getUserId()))
            throw new RequestException(HttpCode.BAD_REQUEST, "账号不能为空！！！");
        int count = userMapper.insert(user);
        if (count != 1)
            throw new ServiceException("数据库内部错误");
        return userMapper.selectByUserId(user.getUserId());
    }

    @Override
    public User modifyUser(User user) {
        User dbUser = userMapper.selectByUserId(user.getUserId());
        user.setUserUuid(dbUser.getUserUuid());
        userMapper.update(user);
        return dbUser;
    }

    /**
     * 登录服务
     *
     * @param user 前端发送过来的user数据
     * @param role 调用本方法的controller提供的用户身份role
     * @return 数据表对应的实体类
     */
    @Override
    public User login(User user, Role role) {
        User dbUser = userMapper.selectByUserIdAndPassword(user.getUserId(), user.getPassword());
        if (ObjectUtil.isNull(dbUser)) {
            // 如果数据库中没有记录，抛出异常
            throw new ServiceException("用户名或密码错误!");
        } else if (dbUser.getRole() != role) {
            // 如果身份错误，抛出异常
            throw new AuthenticationException("用户身份错误！");
        } else {
            // 用户信息正确，生成token
            String token = TokenUtil.createToken(user.getUserId(), user.getPassword());
            dbUser.setToken(token);
            return dbUser;
        }
    }

    /**
     * 注册服务
     *
     * @param user 用户信息
     * @param role 用户实身份
     * @return 注册成功后返回用户对象
     */
    @Override
    public User register(User user, Role role) {
        User dbUser = userMapper.selectByUserId(user.getUserId());
        if (!ObjectUtil.isNull(dbUser)) {
            // 如果数据库中有了记录，抛出异常
            throw new ServiceException("账户已存在!");
        } else {
            // 填充属性
            user.setRole(role);
            user.setUserName("用户" + user.getUserId().toString());
            // 检验
            int count = userMapper.insert(user);
            if (count != 1) {
                throw new ServiceException("数据库内部错误!");
            } else {
                return user;
            }
        }
    }

    /**
     * 重置密码
     *
     * @param user 前端用户信息
     * @return 数据库user记录
     */
    @Override
    public User resetPassword(User user) {
        Integer userId = user.getUserId();
        String password = user.getPassword();
        User dbUser = userMapper.selectByUserId(userId);

        // 根据userUuid修改密码
        int count = userMapper.updatePasswordByUserUuid(password, dbUser.getUserUuid());
        if (count != 1) {
            throw new ServiceException("数据库错误，密码修改失败");
        }
        // 更新token并返回。
        dbUser = userMapper.selectByUserId(userId);
        String token = TokenUtil.createToken(dbUser.getUserId(), dbUser.getPassword());
        dbUser.setToken(token);
        return dbUser;
    }

    /**
     * 修改图片路径
     *
     * @param user 用户
     * @return 封装好的数据库User
     */
    @Override
    public User modifyImagePath(User user) {
        Integer userId = user.getUserId();
        User dbUser = userMapper.selectByUserId(userId);
        int count = userMapper.updateImagePathByUserUuid(user.getImagePath(), dbUser.getUserUuid());
        if (count != 1) {
            throw new ServiceException("数据库错误，图片路径修改失败");
        }
        dbUser.setToken(user.getToken());
        dbUser.setImagePath(user.getImagePath());
        return dbUser;
    }

    /**
     * 修改用户名
     *
     * @param user 用户
     * @return 封装好的数据库User
     */
    @Override
    public User modifyUserName(User user) {
        Integer userId = user.getUserId();
        String userName = user.getUserName();
        // 根据userUuid修改用户名
        User dbUser = userMapper.selectByUserId(userId);
        int count = userMapper.updateUsernameByUserUuid(userName, dbUser.getUserUuid());
        if (count != 1) {
            throw new ServiceException("数据库错误，用户名修改失败");
        }
        // 将token补齐并返回。
        dbUser = userMapper.selectByUserId(userId);
        dbUser.setToken(user.getToken());
        return dbUser;
    }

    /**
     * 修改密码
     *
     * @param user        用户
     * @param oldPassword 原密码
     * @return 封装好的数据库User
     */
    @Override
    public User modifyPassword(User user, String oldPassword) {
        Integer userId = user.getUserId();
        String newPassword = user.getPassword();
        User dbUser = userMapper.selectByUserId(userId);

        if (!oldPassword.equals(dbUser.getPassword())) {
            // 如果原密码错误，报错。
            throw new AuthenticationException("原密码错误");
        }
        if (newPassword.equals(oldPassword)) {
            // 新旧密码相同，报错
            throw new RequestException(HttpCode.BAD_REQUEST, "新旧密码相同");
        }
        // 根据userUuid修改密码
        int count = userMapper.updatePasswordByUserUuid(newPassword, dbUser.getUserUuid());
        if (count != 1) {
            throw new ServiceException("数据库错误，密码修改失败");
        }
        // 更新token并返回。
        dbUser = userMapper.selectByUserId(userId);
        String token = TokenUtil.createToken(dbUser.getUserId(), dbUser.getPassword());
        dbUser.setToken(token);
        return dbUser;
    }

    @Override
    public void deleteByUserId(int userId) {
        User dbUser = userMapper.selectByUserId(userId);
        int count = userMapper.deleteByUserUuid(dbUser.getUserUuid());
        if (count != 1) {
            throw new ServiceException("数据库内部错误");
        }
    }

}
